/**
 * @author Daniel Monteiro
 * */

package br.odb.bzk3.android;

import java.util.ArrayList;
import java.util.Vector;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;
import br.odb.bzk3.geometry.GameActor;
import br.odb.libscene.Sector;

public class GLESRenderer implements GLSurfaceView.Renderer {
	// <OpenGL ES stuff?>
	private static final String LOG_TAG = GLESRenderer.class.getSimpleName();
	// </OpenGL ES stuff?>


	private ArrayList<GameSector> sectorsToRender;
	private ArrayList<Square> squaresToRender;
	private ArrayList<GameActor> actors;
	public ArrayList<Triangle> shapes;
	private float angle;
	public GameActor cameraActor;
	private String displayList;

	// ------------------------------------------------------------------------------------------------------------
	public String toString() {
		return displayList;
	}

	// ------------------------------------------------------------------------------------------------------------

	public void addToScene(GameSector sector) {
		sectorsToRender.add(sector);
	}

	// ------------------------------------------------------------------------------------------------------------
	public GLESRenderer() {
		sectorsToRender = new ArrayList<GameSector>();
		squaresToRender = new ArrayList<Square>();
		actors = new ArrayList<GameActor>();
		shapes = new ArrayList<Triangle>();
	}

	// ------------------------------------------------------------------------------------------------------------
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glShadeModel(GL10.GL_SMOOTH);
		;
		gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		gl.glClearDepthf(1.0f);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glDepthFunc(GL10.GL_LEQUAL);
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
	}

	// ------------------------------------------------------------------------------------------------------------
	public void buildScene() {
		displayList = new String("");
		Square square;
		GameSector sector;
		// /master sector ja ficou de fora no momento em que não fui
		// addToScene'ed
		for (int c = 0; c < this.sectorsToRender.size(); c++) {

			sector = sectorsToRender.get(c);

			for (int d = 0; d < 6; d++)
				if (sector.getLink(d) == Sector.NO_LINK ) {
					
					square = null;
					
					switch (d) {
					case 0:
						square = SquareFactory.MakeXY(sector.getX0(), sector.getY0(),
								sector.getX1(), sector.getY1(), sector.getZ0(),
								0);
						break;
					case 2:
						square = SquareFactory.MakeXY(sector.getX0(), sector.getY0(),
								sector.getX1(), sector.getY1(), sector.getZ1(),
								0);
						break;
					case 1:
						square = SquareFactory.MakeYZ(sector.getY0(), sector.getZ0(),
								sector.getY1(), sector.getZ1(), sector.getX0(),
								0);
						break;
					case 3:
						square = SquareFactory.MakeYZ(sector.getY0(), sector.getZ0(),
								sector.getY1(), sector.getZ1(), sector.getX1(),
								0);
						break;
					case 4:
						square = SquareFactory.MakeXZ(sector.getX0(), sector.getZ0(),
								sector.getX1(), sector.getZ1(), sector.getY0(),
								0);
						break;
					case 5:
						square = SquareFactory.MakeXZ(sector.getX0(), sector.getZ0(),
								sector.getX1(), sector.getZ1(), sector.getY1(),
								0);
						break;
					}

					square.setColor(sector.getColor(d).getR() / 255.0f,
							sector.getColor(d).getG() / 255.0f,
							sector.getColor(d).getB() / 255.0f, 1.0f);

					sector.iFaces[d] = square;
					this.squaresToRender.add(square);
				}

		}
	}

	private void setCamera( GL10 gl ) {
		gl.glLoadIdentity();
		gl.glRotatef(angle, 0, 1, 0);
		gl.glTranslatef(-this.cameraActor.startPoint.x,
				-this.cameraActor.startPoint.y,
				-this.cameraActor.startPoint.z);
	}
	
	// ------------------------------------------------------------------------------------------------------------
	public void renderScene(GL10 gl) {
		

		
		Square square;
		Triangle t;
		gl.glEnable(GL10.GL_DEPTH_TEST);
		for (int c = 0; c < this.squaresToRender.size(); c++) {
			square = ((Square) this.squaresToRender.get(c));

			gl.glColor4f(square.getColor(0), square.getColor(1),
					square.getColor(2), square.getColor(3) );
			square.draw(gl);
		}

		GameActor actor;

		ObjMesh trigs;
		Triangle trig;
		for (int c = 1; c < this.actors.size(); ++c ) {
			actor = actors.get( c );

			trigs = (ObjMesh) actor.getMesh().get( 0 );

			gl.glTranslatef( actor.startPoint.x, actor.startPoint.y, actor.startPoint.z );
			gl.glRotatef( actor.angle * 22.5f, 0.0f, 1.0f, 0.0f );
			for ( int d = 0; d < trigs.getMesh().size(); ++d ) {
				trig = (Triangle) trigs.getMesh().elementAt( d );
				trig.draw( gl );
			}
			gl.glTranslatef( -actor.startPoint.x, -actor.startPoint.y, -actor.startPoint.z );
			gl.glRotatef( -actor.angle * 22.5f, 0.0f, 1.0f, 0.0f );
		}

		gl.glDisable(GL10.GL_DEPTH_TEST);
		gl.glLoadIdentity();
		for (int c = 0; c < shapes.size(); ++c) {
			t = shapes.get(c);
			t.draw(gl);
		}
	}

	// ------------------------------------------------------------------------------------------------------------
	public void onDrawFrame(GL10 gl) {
		
//		if ( EngineView.loaded )
//			return;
		
		synchronized ( this ) {
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
			setCamera( gl );
			
//			Log.d("BZK3", "camera: " + cameraActor.iStartPoint.toString()  );
			// for (int c = 0; c < lightEmissors.size(); c++)
			// if (lightEmissors.get(c).candelas > 0)
			// lit(lightEmissors.get(c).Sector-1, lightEmissors.get(c).candelas);

			for (int c = 0; c < this.sectorsToRender.size(); c++) {

				((GameSector) this.sectorsToRender.get(c)).lit();
			}

			this.renderScene(gl);

			for (int c = 0; c < this.sectorsToRender.size(); c++) {

				((GameSector) this.sectorsToRender.get(c)).reset();

			}
		}
	}


	private void lit(int sector, short candelas) {
		GameSector sec = (GameSector) this.sectorsToRender.get(sector);

		short factor = (short) (candelas - 5);

		sec.addCandelas( factor );

		factor -= sec.VisibleFaces * 5;

		for ( int c = 0; c < 6; ++c ) {
			if (sec.getLink(c) !=  Sector.NO_LINK ) {
				lit( sec.getLink(c) - 1, factor);

			}
		}

	}

	// ------------------------------------------------------------------------------------------------------------
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		if (height == 0) {
			height = 1;
		}

		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();

		GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
				255.0f);

		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();
	}

	// ------------------------------------------------------------------------------------------------------------
	public void setAngle(float Angle) {
		angle = Angle;
	}

	// ------------------------------------------------------------------------------------------------------------a


	public void addToScene(GameActor actor) {
		actors.add(actor);
	}


	public void setCurrentCamera( GameActor cameraActor ) {
		this.cameraActor = cameraActor;		
	}
}
